import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.GlobalEventExecutor;

public class ChatServer {
    static final int PORT = 8888;
    static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    public static void chatServerStart() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 添加行解码器解决粘包问题
                            pipeline.addLast(new LineBasedFrameDecoder(1024));
                            pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
                            pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
                            pipeline.addLast(new ChatServerHandler());
                        }
                    });

            ChannelFuture f = b.bind(PORT).sync();
            System.out.println("Run: Server");
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    static class ChatServerHandler extends SimpleChannelInboundHandler<String> {
        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            // 新连接加入时广播上线通知
            String msg = "客户[" + ctx.channel().remoteAddress() + "]上线";
            clients.add(ctx.channel());
            clients.writeAndFlush(msg + "\n");
            System.out.println(msg);

            // 向新客户端发送欢迎消息
            ctx.writeAndFlush("欢迎您上线\n");
        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) {
            // 广播收到的消息
            String formattedMsg = "客户[" + ctx.channel().remoteAddress() + "]消息：" + msg;
            clients.writeAndFlush(formattedMsg + "\n");
            System.out.println(formattedMsg);
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            // 连接断开时广播下线通知
            String msg = "客户[" + ctx.channel().remoteAddress() + "]下线";
            clients.remove(ctx.channel());
            clients.writeAndFlush(msg + "\n");
            System.out.println(msg);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
}